////////////////////////////////////////////////
// DESCRIPTION:
//     Device Notfication support classes
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//
#include <FusionWare\Win32.h>
#include <pnp.h>

namespace FusionWare
{
    namespace Win32
    {
        //////////////////////////////////////////////////////////
        // Description:
        //    Class to manage Device manager PNP notifications
        //   
        // Remarks:
        //   There are two ways to use this; class single threaded
        //   and multi-threaded.
        //
        //   Single threaded applications can simply call the
        //   static RequestNotifications() function to receive
        //   notifications through the call back provided.
        //   
        //   Multi-threaded apps, drivers and services create an
        //   instance of this class and use the StartNotifications
        //   method to start the thread, which will in turn call into
        //   the provided "call back" function for each notification
        //   received. When shutting down, the StopNotifications() will
        //   disconnect from the device manager notifications and
        //   stop the thread created in StartNotifications()
        //
        class CDeviceNotifications : protected FusionWare::Threads::Thread
        {
        public:
            typedef Loki::Functor<void, TYPELIST_2(const DEVDETAIL&, DWORD)> DeviceNotificationFunction;

            CDeviceNotifications() 
            : GetAll(FALSE)
            {
                memset(&this->Guid, 0, sizeof(this->Guid));
            }

            ///////////////////////////////////////////////////////
            // Description: 
            // 
            // Input: 
            //     pFunc    - Pointer to call back function to receive the notifications
            //     Guid     - Desired Guid for notifications
            //     Priority - Priority of the thread
            //     PriExt   - true if CeSetTHreadPriority should be used otherwise
            //                SetThreadPriority is used.
            //     GetAll   - Indicates if all current notifications for the Guid should be 
            //                processed. If false then only new notifications are sent.
            //
            // Remarks: 
            //     Creates an OS thread associted with this thread object and runs the
            //     internal NotificationThread() method which in turn calls RequestNotifications()
            //     with the appropriate paramaters provided. In essence this creates a thread
            //     context to call the static RequestNotifications on and provides a means of
            //     stopping the thread. 
            //
            bool StartNotifications(DeviceNotificationFunction pFunc
                                   , const GUID& Guid
                                   , int priority  = THREAD_PRIORITY_NORMAL
                                   , bool PriExt   = false
                                   , bool GetAll   = TRUE);
    
            ///////////////////////////////////////////////////////
            // Description: 
            //    Stops the thread
            //
            // Input: 
            //    TimeOut=INFINITE - TimeOut to wait for thread to stop
            //
            // Remarks: 
            //     
            // Note: 
            //     
            bool StopNotifications(DWORD TimeOut=INFINITE);

            ///////////////////////////////////////////////////////
            // Description: 
            // 
            // Input: 
            //    pFunc            - Pointer to call back function to receive the notifications 
            //    Guid             - Desired Guid for notifications                             
            //    TimeOut=INFINITE - Timeout for reads of the notification MessageQueue
            //    GetAll=TRUE      - Indicates if all current notifications for the Guid should be
            //                       processed. If false then only new notifications are sent.    
            //    hStopEvent=NULL  - Handle to an event used to break out of notification loop
            //
            // Remarks: 
            //    The hStopEvent paramater allows another thread to trigger the notification read
            //    loop to stop processing messages and return from this method. This is used by the
            //    multi-threading methods of the class. It may also be useful for other situations
            //    where finer control over the loop code or an existing thread and stop event exists
            //    already.
            //
            static bool RequestNotifications(DeviceNotificationFunction pFunc, const GUID& Guid, DWORD TimeOut=INFINITE, bool GetAll=TRUE, HANDLE hStopEvent=NULL);

        protected:
            DWORD NotificationThread(DeviceNotificationFunction NotifFunc);

            GUID Guid;
            bool GetAll;
            FusionWare::Threads::Event StopEvent;
        };
    }
}